package com.settlement.system.controller;

import cn.hutool.Hutool;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.settlement.system.common.util.SecurityUtils;
import com.settlement.system.common.util.common.DictionaryUtil;
import com.settlement.system.csv.CsvExportBuilder;
import com.settlement.system.csv.CsvExportUtil;
import com.settlement.system.common.enums.AccountStatusEnum;
import com.settlement.system.common.enums.CostAllocationEnum;
import com.settlement.system.common.enums.ExcelFileType;
import com.settlement.system.common.enums.ReturnStatusEnum;
import com.settlement.system.common.exception.ServiceException;
import com.settlement.system.mapper.security.userdetails.SysUserDetails;
import com.settlement.system.model.entity.common.*;
import com.settlement.system.reply.ObjectDataResponse;
import com.settlement.system.service.*;
import com.settlement.system.service.csv.DateSpiltCsvDatas;
import com.settlement.system.common.util.common.FasUtil;
import com.settlement.system.common.util.common.SystemUserUtil;
import com.alibaba.excel.context.AnalysisContext;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * RR-费用分摊表 前端控制器
 * @author xiaochuan
 * @since 2023-01-06
 */

@Slf4j
@Api(tags = "RR-费用分摊表",description = "RR-费用分摊表")
@RestController
@RequestMapping("/tblCostAllocationDetail")
public class TblCostAllocationDetailController extends ExcelController<TblCostAllocationDetail> {

    @Value("${system.export-root.path}")
    private String exportRootPath;

    @Resource
    private ITblReceiveRefundSupplierService tblReceiveRefundSupplierService;

    @Resource
    private ITblRrBillTypeService tblRrBillTypeService;

    @Resource
    private ITblCostAllocationDetailService tblCostAllocationDetailService;

    @Resource
    private ITblReceiveRefundShopService tblReceiveRefundShopService;

    @Resource
    private ITblRrChannelService tblRrChannelService;

    @Resource
    private IBrandService brandService;

    @Resource
    private IBrandUnitService brandUnitService;

    @Resource
    private DictionaryUtil dictionaryUtil;

    private ExecutorService executors = Executors.newFixedThreadPool(1);

    @Override
    public IBaseService init() {
        return tblCostAllocationDetailService;
    }

    @Override
    public Class<?> getModelClass() {
        return TblCostAllocationDetail.class;
    }

    @Override
    protected void setParamsModel(Map<String, Object> model) {
        String nameShort = dictionaryUtil.getNameShortShowChildBrandName();
        if(org.apache.commons.lang3.StringUtils.isNotEmpty(nameShort)){
            model.put("nameShort",nameShort);
        }

        FasUtil.formatInQueryCondition(model,
                "channelNo","shopNo",
                "recordAccountProject","voucherType",
                "accountStatus","pushFasStatus",
                "accountingPeriod","companyNo",
                "sourceType","createUser","nameShort"
        );
        String summaryId = (String) model.get("summaryId");
        if(StringUtils.isNotEmpty(summaryId) && summaryId.contains(",")){
            String[] split = summaryId.split(",");
            List<String> summaryIdList = Arrays.asList(split);
            model.put("summaryIdList",summaryIdList);
        }

        super.setParamsModel(model);
    }

    @Override
    protected void setFootModel(Map<String, Object> result, Map<String, Object> model) throws ServiceException {
        TblCostAllocationDetail foot = tblCostAllocationDetailService.getFoot(model);
        result.put("foot", foot==null? getModelClass():foot);
    }

    @Override
    public void exportExcel(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, Object> params = buildParam(request);
        setParamsModel(params);
        Object fileName = "RR-费用分摊表";
        String path = exportRootPath + System.currentTimeMillis() + File.separator;
        CsvExportUtil.createCsv()
                .headClass(TblCostAllocationDetail.class)
                .fileName(fileName.toString())
                .fileType(ExcelFileType.XLSX)
                .model(CsvExportBuilder.MULTI_ZIP_MODEL)
                .parentPath(path)
                .csvDatas(new DateSpiltCsvDatas(tblCostAllocationDetailService, params))
                .export(request, response);
    }

    @Override
    public void exportExcelPost(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, Object> params) throws Exception {
        setParamsModel(params);
        String fileName = "RR-费用分摊表";
        String path = exportRootPath + System.currentTimeMillis() + File.separator;
        CsvExportUtil.createCsv()
                .headClass(TblCostAllocationDetail.class)
                .fileName(fileName)
                .fileType(ExcelFileType.XLSX)
                .model(CsvExportBuilder.MULTI_ZIP_MODEL)
                .parentPath(path)
                .csvDatas(new DateSpiltCsvDatas(tblCostAllocationDetailService, params))
                .export(request, response);
    }

    @Override
    public String verifyImportObject(TblCostAllocationDetail tblCostAllocationDetail, AnalysisContext analysisContext) {

        if(!"导入模板".equals(analysisContext.readSheetHolder().getSheetName())){
            return null;
        }

        try{
            String s = super.verifyImportObject(tblCostAllocationDetail, analysisContext);
            if(StringUtils.isNotEmpty(s)){
                return s;
            }

            Map<String, Object> map = new HashMap<>();
            map.put("id",tblCostAllocationDetail.getId());
            FasUtil.formatInQueryCondition(map,"id");
            dictionaryUtil.setSysDictParam(map);
            List<TblCostAllocationDetail> details = tblCostAllocationDetailService.selectByParam(map);

            if(!"是".equals(tblCostAllocationDetail.getIfOriginData()) && !"否".equals(tblCostAllocationDetail.getIfOriginData())){
                return "[是否原数据相反数]的值为“是”或“否”。";
            }

            String brandUnitNo = tblCostAllocationDetail.getBrandUnitNo();
            BrandUnit byBrandUnitNo = brandUnitService.getByBrandUnitNo(brandUnitNo);
            if(byBrandUnitNo == null){
                return "品牌部编码不正确或未配置";
            }

            String billType = tblCostAllocationDetail.getBillType();
            String billTypeNo = tblRrBillTypeService.getNoByName(billType);
            if(org.apache.commons.lang3.StringUtils.isEmpty(billTypeNo)){
                return "[账单类型]必须在【RR-账单类型】存在“账单类型”，请确认后导入";
            }
            tblCostAllocationDetail.setBillType(billTypeNo);

            List<TblReceiveRefundSupplier> tblReceiveRefundSuppliers = tblReceiveRefundSupplierService
                    .selectByNcSupplierRecord(tblCostAllocationDetail.getNcSupplierRecord());
            if(CollectionUtils.isEmpty(tblReceiveRefundSuppliers)){
                return "NC供应商档案必须为【RR-供应商设置】中的供应商档案";
            }

            if(CollectionUtils.isEmpty(details)){
                return "[唯一ID]在【RR-费用分摊表】表中不存在。";
            }

            if(tblCostAllocationDetail.getNoTaxAmount().add(tblCostAllocationDetail.getTaxAmount()).compareTo(tblCostAllocationDetail.getShareAmount())!=0){
                return "税额=分摊金额-不含税金额";
            }

            List<String> accountStatusList = new ArrayList<>();
            StringBuffer sbWeightId = new StringBuffer();
            StringBuffer sbSummaryId = new StringBuffer();
            if(!CollectionUtils.isEmpty(details)){
                for (TblCostAllocationDetail detail : details) {
                    if(!detail.getAccountStatus().equals(AccountStatusEnum.T0_NOT_CREATED.getNo()) ||
                            !( detail.getPushFasStatus().equals(CostAllocationEnum.PushFasStatusEnum.T0_NOT_NEED_PUSHING.getNo()) ||
                               detail.getPushFasStatus().equals(CostAllocationEnum.PushFasStatusEnum.T1_NOT_PUSHED.getNo())
                             )){

                        return "[唯一ID]对应 的记账状态必须是“未生成凭证”，推送FAS状态 必须是\"无需推送\"，或“未推送“状态。";
                    }else{
                        if(accountStatusList.isEmpty()){
                            accountStatusList.add(detail.getAccountStatus());
                        }else{
                            if(!accountStatusList.contains(detail.getAccountStatus())){
                                return "导入的数据若存在一行 中有2个及以上唯一ID，唯一ID]\"记账状态\"应一致，不一致的不允许导入调整。";
                            }
                        }
                        if(StringUtils.isNotEmpty(detail.getWeightId())){
                            sbWeightId.append(","+detail.getWeightId());
                        }
                        if(StringUtils.isNotEmpty(detail.getSummaryId()) && !sbSummaryId.toString().contains(detail.getSummaryId())){
                            sbSummaryId.append(","+detail.getSummaryId());
                        }
                    }
                }
            }

            TblCostAllocationDetail detailExist = details.get(0);
            tblCostAllocationDetail.setAccountStatus(detailExist.getAccountStatus());
            tblCostAllocationDetail.setPushFasStatus(detailExist.getPushFasStatus());
            if(StringUtils.isNotEmpty(sbWeightId) && StringUtils.startsWith(sbWeightId,",")){
                String weightId = sbWeightId.toString().substring(1);
                tblCostAllocationDetail.setWeightId(weightId);
            }
            if(StringUtils.isNotEmpty(sbSummaryId) && StringUtils.startsWith(sbSummaryId,",")){
                String summaryId = sbSummaryId.toString().substring(1);
                tblCostAllocationDetail.setSummaryId(summaryId);
            }
            tblCostAllocationDetail.setRefId(tblCostAllocationDetail.getId());

            List<String> nameShortShowChildBrandNameList = dictionaryUtil.getNameShortShowChildBrandNameList();
            if(!CollectionUtils.isEmpty(nameShortShowChildBrandNameList) &&
                    nameShortShowChildBrandNameList.contains(tblCostAllocationDetail.getBrandUnitNo())) {
                if (StringUtils.isEmpty(tblCostAllocationDetail.getBrandNo())) {
                    return "品牌编码不能为空";
                }

                Brand brandByNo = brandService.getBrandByNo(tblCostAllocationDetail.getBrandNo());
                if(brandByNo == null){
                    return "品牌编码不正确或未配置";
                }
            }

            if("是".equals(tblCostAllocationDetail.getIfOriginData())){
                boolean ok = tblCostAllocationDetail.getId().equals(detailExist.getId()) &&
                        tblCostAllocationDetail.getWeightType().equals(detailExist.getWeightType()) &&
                        tblCostAllocationDetail.getAccountingPeriod().getTime() == detailExist.getAccountingPeriod().getTime() &&
                        tblCostAllocationDetail.getCompanyNo().equals(detailExist.getCompanyNo()) &&
                        tblCostAllocationDetail.getChannelName().equals(detailExist.getChannelName()) &&
                        tblCostAllocationDetail.getShopNo().equals(detailExist.getShopNo()) &&
                        tblCostAllocationDetail.getRecordAccountProject().equals(detailExist.getRecordAccountProject()) &&
                        tblCostAllocationDetail.getVoucherType().equals(detailExist.getVoucherType()) &&
                        tblCostAllocationDetail.getBeforeOrAfterTicket().equals(detailExist.getBeforeOrAfterTicket()) &&
                        tblCostAllocationDetail.getBrandUnitNo().equals(detailExist.getBrandUnitNo()) &&
                        !(
                            !CollectionUtils.isEmpty(nameShortShowChildBrandNameList) &&
                            nameShortShowChildBrandNameList.contains(tblCostAllocationDetail.getBrandUnitNo()) &&
                            !StrUtil.equals(tblCostAllocationDetail.getBrandNo(),detailExist.getBrandNo())
                        ) &&
                        tblCostAllocationDetail.getShareAmount().multiply(new BigDecimal("-1")).compareTo(detailExist.getShareAmount())==0 &&
                        tblCostAllocationDetail.getNoTaxAmount().multiply(new BigDecimal("-1")).compareTo(detailExist.getNoTaxAmount())==0 &&
                        tblCostAllocationDetail.getTaxAmount().multiply(new BigDecimal("-1")).compareTo(detailExist.getTaxAmount())==0;

                if(!ok){
                    return "[是否原数据相反数]=“是”的部分，按[唯一ID]校验，导入的记录的非数值字段与原记录字段都需要保持一致，且金额相反";
                }
            }

            if(StringUtils.isEmpty(tblCostAllocationDetail.getShopName())){
                TblReceiveRefundShop shop = tblReceiveRefundShopService.getByShopNo(tblCostAllocationDetail.getShopNo());
                if(shop!=null){
                    tblCostAllocationDetail.setShopName(shop.getShopName());
                }
            }

            String channelNo = tblRrChannelService.getNoByName(tblCostAllocationDetail.getChannelName());
            tblCostAllocationDetail.setChannelNo(channelNo);
            tblCostAllocationDetail.setId(null);
            tblCostAllocationDetail.setSourceType(CostAllocationEnum.SourceTypeEnum.T1_ADJUST.getNo());

            String ncBrandNo = tblCostAllocationDetail.getNcBrandNo();
            String ncBrandNameByNcBrandNo = tblCostAllocationDetailService.getNcBrandNameByNcBrandNo(ncBrandNo);
            tblCostAllocationDetail.setNcBrandName(ncBrandNameByNcBrandNo);



        }catch (Exception ex){
            log.error("导入失败",ex);
            return "导入校验失败";
        }

        return null;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    protected void saveData(List<TblCostAllocationDetail> datas, AnalysisContext analysisContext) throws ServiceException {
        try{
            if(!"导入模板".equals(analysisContext.readSheetHolder().getSheetName())){
                return;
            }
            super.saveData(datas);
        }catch (Exception ex){
            log.error("导入数据异常", ex);
            throw new ServiceException("导入数据异常", ex);
        }
    }

    @Override
    protected String validateAllDate(List<TblCostAllocationDetail> datas,AnalysisContext analysisContext) {
        if(!"导入模板".equals(analysisContext.readSheetHolder().getSheetName())){
            return null;
        }
        Map<String, List<TblCostAllocationDetail>> collect = datas.stream().collect(Collectors.groupingBy(TblCostAllocationDetail::getRefId));
        for (Map.Entry<String, List<TblCostAllocationDetail>> stringListEntry : collect.entrySet()) {
            List<TblCostAllocationDetail> value = stringListEntry.getValue();
            int yesSize = value.stream().filter(s -> "是".equals(s.getIfOriginData())).collect(Collectors.toList()).size();
            int noSize = value.stream().filter(s -> "否".equals(s.getIfOriginData())).collect(Collectors.toList()).size();
            if(yesSize < 1 || noSize < 1){
                return "1个唯一ID，导入明细行中[是否原数据相反数]必须有\"是\"也有\"否\"";
            }
            if(yesSize != 1){
                return "1个唯一ID只能有1行[是否原数据相反数]=“是”的";
            }
        }

        BigDecimal totalShareAmount = BigDecimal.ZERO;
        BigDecimal totalNoTaxAmount = BigDecimal.ZERO;

        for (TblCostAllocationDetail data : datas) {
            totalShareAmount = totalShareAmount.add(data.getShareAmount());
            totalNoTaxAmount = totalNoTaxAmount.add(data.getNoTaxAmount());
        }

        if(totalShareAmount.compareTo(BigDecimal.ZERO)!=0){
            return "整体导入文件中的数据中[分摊金额]合计应为0";
        }

        if(totalNoTaxAmount.compareTo(BigDecimal.ZERO)!=0){
            return "整体导入文件中的数据中[不含税金额]合计应为0";
        }

        return super.validateAllDate(datas);
    }

    @ApiOperation("删除数据")
    @RequestMapping(value = "deleteByParams", method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse deleteByParams(@RequestBody Map<String, Object> model, HttpServletRequest request) {
        try {
            setParamsModel(model);
            SysUserDetails user = SecurityUtils.getUser();;
            Map<String,Object> params = new HashMap<>(model);
            params.put("createUserName",user.getUsername());
            params.put("updateUser",user.getUsername());

            String message = tblCostAllocationDetailService.checkBeforeDelete(params);
            if (org.apache.commons.lang3.StringUtils.isEmpty(message)) {
                return new ObjectDataResponse(ReturnStatusEnum.REQUEST_SUCCESS);
            } else {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), message);
            }
        } catch (Exception ex) {
            log.info("更新数据异常", ex);
            return new ObjectDataResponse(ReturnStatusEnum.REQUEST_ABNORMAL);
        }
    }

    @ApiOperation("推送FAS")
    @RequestMapping(value = "pushToFas", method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse pushToFas(@RequestBody Map<String, Object> model, HttpServletRequest request) {
        try {
            setParamsModel(model);
            SysUserDetails user = SecurityUtils.getUser();;
            Map<String,Object> params = new HashMap<>(model);
            params.put("updateUser",user.getUsername());

            String message = tblCostAllocationDetailService.checkBeforePushToFas(params);
            if (org.apache.commons.lang3.StringUtils.isEmpty(message)) {
                return new ObjectDataResponse(ReturnStatusEnum.REQUEST_SUCCESS);
            } else {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), message);
            }
        } catch (Exception ex) {
            log.info("更新数据异常", ex);
            return new ObjectDataResponse(ReturnStatusEnum.REQUEST_ABNORMAL);
        }
    }

    @ApiOperation("删除FAS票前费用")
    @RequestMapping(value = "deleteFromFas", method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse deleteFromFas(@RequestBody Map<String, Object> model, HttpServletRequest request) {
        try {
            setParamsModel(model);
            SysUserDetails user = SecurityUtils.getUser();;
            Map<String,Object> params = new HashMap<>(model);
            params.put("updateUser",user.getUsername());

            String message = tblCostAllocationDetailService.checkBeforeDeleteFromFas(params);
            if (org.apache.commons.lang3.StringUtils.isEmpty(message)) {
                return new ObjectDataResponse(ReturnStatusEnum.REQUEST_SUCCESS);
            } else {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), message);
            }
        } catch (Exception ex) {
            log.info("更新数据异常", ex);
            return new ObjectDataResponse(ReturnStatusEnum.REQUEST_ABNORMAL);
        }
    }

    @ApiOperation("生成NC凭证")
    @RequestMapping(value = "produceNc", method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse produceNc(@RequestBody Map<String, Object> model, HttpServletRequest request) {
        try {
            setParamsModel(model);
            String message = tblCostAllocationDetailService.produceNc(model);
            if (org.apache.commons.lang3.StringUtils.isEmpty(message)) {
                return new ObjectDataResponse(ReturnStatusEnum.REQUEST_SUCCESS);
            } else {
                return new ObjectDataResponse(ReturnStatusEnum.REQUEST_ABNORMAL.getValue(), message);
            }
        } catch (Exception ex) {
            log.info("更新数据异常", ex);
            return new ObjectDataResponse(ReturnStatusEnum.REQUEST_ABNORMAL);
        }
    }

    @ApiOperation("获取权数中的会计期间")
    @RequestMapping("selectExistAccountPeriod")
    public ObjectDataResponse selectExistAccountPeriod(){
        Map<String,Object> result = new HashMap<>(16);
        try {
            List<CommonPlugIn> rows = tblCostAllocationDetailService.selectExistAccountPeriod();
            result.put("rows",rows);
            result.put("total",rows.size());
            return new ObjectDataResponse<Map>(result,200,"获取列表成功");
        } catch (Exception ex){
            log.error("获取列表出错",ex);
            return new ObjectDataResponse(500,"获取列表失败，请联系管理员！");
        }
    }
}

